import React from 'react';
import './style.less';
import Button from 'cui/Button';
import Notice from 'cui/Notice';
import Dialog from 'cui/Dialog';
import Form from 'cui/Form';
import FormItem from 'cui/FormItem';
import {transformGeojson} from '../components/utils/Utils';
import Map from 'ol/Map';
import MousePosition from 'ol/control/MousePosition';
import {defaults as defaultControls} from 'ol/control';
import {Stroke, Fill, Style} from 'ol/style';
import {createStringXY} from 'ol/coordinate';
import {Vector as VectorSource} from 'ol/source';
import {Vector as VectorLayer} from 'ol/layer';
import GeoJSON from 'ol/format/GeoJSON';
import epsg from '../data/epsg.json';
import marsCoords from '../data/gcoord.json';
const { remote, ipcRenderer} = require('electron');
const dialog = remote.dialog;
const path = require('path');
const gcoord = require('gcoord');
const fs = require('fs');
const turf = require('@turf/helpers');
import simplify from '@turf/simplify';
const lineOverlap = require('@turf/line-overlap').default;
const lineSplit = require('@turf/line-split').default;
const booleanContains = require('@turf/boolean-contains').default;
const lineIntersect = require('@turf/line-intersect').default;
const lineSlice = require('@turf/line-slice').default;
const difference = require('@turf/difference').default;
const union = require('@turf/union').default;
const polygonToLine = require('@turf/polygon-to-line').default;
const lineToPolygon = require('@turf/line-to-polygon').default;
import regions from './region';
import 'ol/ol.css';
import 'cui/Select';

class SHP extends React.Component {
    displayName = 'SHP';

    jsons = {};

    state = {
        showModal: false,
        showMarsModal: false,
        showCXModal: false
    }

    transformParams = {
        currentProjection: '',
        targetCSR: ''
    }

    transformMars = {
        current: '',
        target: ''
    }

    cxParams = {
        precision: 0.1
    }

    componentDidMount () {
        // if (!this.map) {
        //     // this.map = L.map('map');
        //     const mousePositionControl = new MousePosition({
        //         coordinateFormat: createStringXY(15),
        //         className: 'custom-mouse-position',
        //         undefinedHTML: '&nbsp;'
        //     });
        //     this.map = new Map({
        //         controls: defaultControls().extend([mousePositionControl]),
        //         target: 'map'
        //     });
        // }
        // this.addGeoJSONLayer(regions);
        // this.jsons[name] = regions;
    }

    openFileSelect = () => {
        dialog.showOpenDialog({
            properties: ['openFile'],
            filters: [
                { name: 'shp文件', extensions: ['shp'] }
            ]
        }).then(result => {
            // 选中shp文件，请求解析成geojson
            if (result.filePaths && result.filePaths.length) {
                const json = ipcRenderer.sendSync('load-shp-file', result.filePaths[0]);
                this.form.setCurrentProjection(json.prj);
                this.createMap(json, result.filePaths[0]);
            }
        }).catch(err => {
            console.log(err);
        });
    }

    /**
     * 根据geojson创建地图
     * @param {*} json 
     */
    createMap (json, filePath) {
        const name = path.basename(filePath, '.shp');
        const data = {
            'type': 'FeatureCollection',
            'features': json.data
        };
        if (!this.map) {
            // this.map = L.map('map');
            const mousePositionControl = new MousePosition({
                coordinateFormat: createStringXY(15),
                className: 'custom-mouse-position',
                undefinedHTML: '&nbsp;'
            });
            this.map = new Map({
                controls: defaultControls().extend([mousePositionControl]),
                target: 'map'
            });
        }
        this.addGeoJSONLayer(data);
        this.jsons[name] = data;
    }

    addGeoJSONLayer (data) {
        const vectorSource = new VectorSource({
            features: new GeoJSON().readFeatures(data)
        });
        
        const colors = ['blue', 'green', 'red', 'black', 'yellow'];
        const vectorLayer = new VectorLayer({
            source: vectorSource,
            style () {
                return new Style({
                    stroke: new Stroke({
                        color: colors[parseInt(Math.random() * 5, 10)],
                        width: 2,
                        opacity: 0.5
                    })
                });
            }
        });
        this.map.addLayer(vectorLayer);
        this.map.getView().fit(vectorSource.getExtent());
    }

    exportGEOJSON = () => {
        if (!Object.keys(this.jsons).length) {
            return;
        }
        dialog.showOpenDialog({
            title: '选中保存目录',
            filters: [
                { name: 'GEOJSON文件', extensions: ['json'] }
            ],
            properties: ['openDirectory', 'createDirectory']
        }).then(result => {
            // 选中shp文件，请求解析成geojson
            if (!result.canceled) {
                this.saveJSONs(result.filePaths[0]);
            }
        }).catch(err => {
            console.log(err);
        });
    }

    /**
     * 将每个图层的geojson进行保存， 按照文件名称进行+.json进行保存
     * @param {*} filePath 
     */
    saveJSONs (filePath) {
        try {
            for (const name in this.jsons) {
                const json = this.jsons[name];
                fs.writeFileSync(path.join(filePath, `${name}.json`), JSON.stringify(json));
            }
            Notice.success({
                duration: 3,
                title: '提示信息',
                content: '导出成功'
            });
        } catch (e) {
            console.log(e);
            Notice.error({
                duration: 3,
                title: '提示信息',
                content: '导出失败'
            });
        }
    }

    openProjectionList = () => {
        this.setState({showModal: true});
    }

    close = () => {
        this.setState({showModal: false});
    }

    onConfirm = async (flag) => {
        if (flag) {
            for (const name in this.jsons) {
                const json = this.jsons[name];
                const newJson = JSON.parse(JSON.stringify(json));
                transformGeojson(newJson, this.transformParams.currentProjection, this.transformParams.targetCSR);
                this.jsons[name] = newJson;
                const layers = this.map.getLayers();
                layers.forEach(layer => {
                    this.map.removeLayer(layer);
                });
                this.addGeoJSONLayer(newJson);
            }
            this.close();
            return;
        }
        this.close();
    }

    openMarsDialog = () => {
        this.setState({showMarsModal: true});
    }
    closeMars = () => {
        this.setState({showMarsModal: false});
    }

    /**
     * 点击确定进行火星坐标转换
     */
    onMarsConfirm = async (flag) => {
        if (flag) {
            if (this.transformMars.current === this.transformMars.target) {
                Notice.info({
                    duration: 3,
                    title: '提示信息',
                    content: '选择的坐标系不能相同'
                });
                return false;
            }
            for (const name in this.jsons) {
                const json = this.jsons[name];
                let newJson = JSON.parse(JSON.stringify(json));
                newJson = gcoord.transform(newJson, gcoord[this.transformMars.current], gcoord[this.transformMars.target]);
                this.jsons[name] = newJson;
                const layers = this.map.getLayers();
                layers.forEach(layer => {
                    this.map.removeLayer(layer);
                });
                this.addGeoJSONLayer(newJson);
            }
            this.closeMars();
            return;
        }
        this.closeMars();
    }

    openCXDialog = () => {
        this.setState({showCXModal: true});
    }

    closeCX = () => {
        this.setState({showCXModal: false});
    }

    spliceLine (line, splitter) {
        const map = {};
        splitter.geometry.coordinates.forEach((point) => {
            map[`${point[0]},${point[1]}`] = true;
        });
        // const splitCoordinates = splitter.geometry.coordinates;
        // const start = `${splitCoordinates[0][0]},${splitCoordinates[0][1]}`;
        // const endP = splitCoordinates[splitCoordinates.length - 1];
        // const end = `${endP[0]},${endP[1]}`;
        // console.log(map[start], map[end]);
        

        const coords = line.geometry.coordinates.filter(p => {
            return !map[`${p[0]},${p[1]}`];
        });
        line.geometry.coordinates = coords;
        return turf.lineString(line.geometry.coordinates);
    }

    onCXConfirm = (flag) => {
        if (flag) {
            for (const name in this.jsons) {
                const json = this.jsons[name];
                const newJson = JSON.parse(JSON.stringify(json));
                const geoms = newJson.features.map(f => {
                    return f.geometry;
                });
                const collection = turf.geometryCollection(geoms);
                const options = {tolerance: this.cxParams.precision, highQuality: false};
                const simplified = simplify(collection, options);
                simplified.geometry.geometries.forEach((g, index) => {
                    newJson.features[index].geometry = g;
                });
                
                this.jsons[name] = newJson;
                const layers = this.map.getLayers();
                layers.forEach(layer => {
                    this.map.removeLayer(layer);
                });
                this.addGeoJSONLayer(newJson);

                // const poys = [];
                // const poyParts = [];
                // newJson.features.forEach((f, index) => {
                //     const poy = f;
                //     const line = polygonToLine(poy);
                //     // line.geometry.coordinates.splice(line.geometry.coordinates.length - 1, 1);
                //     poys.push(line);
                //     poyParts[index] = {
                //         orign: line,
                //         orignPoy: poy,
                //         intersects: []
                //     };
                // });
                // const layers = this.map.getLayers();
                // layers.forEach(layer => {
                //     this.map.removeLayer(layer);
                // });
                // const interMap = {};
                // poys.forEach((poy, index) => {
                //     poys.forEach((next, i) => {
                //         if (index !== i) {
                //             const intersection = lineIntersect(poy, next);
                //             if (intersection.features.length) {
                //                 let startIndex = -1;
                //                 let endIndex = -1;
                //                 for (let i = 0; i < intersection.features.length; i++) {
                //                     if (booleanContains(poy, intersection.features[i])) {
                //                         startIndex = i;
                //                         break;
                //                     }
                //                 }
                //                 for (let i = intersection.features.length - 1; i >= 0; i--) {
                //                     if (booleanContains(poy, intersection.features[i])) {
                //                         endIndex = i;
                //                         break;
                //                     }
                //                 }
                                
                //                 console.log(startIndex, endIndex);
                                
                //                 const startF = intersection.features[startIndex];
                //                 const endF = intersection.features[endIndex];
                //                 // const start = turf.point(startF.geometry.coordinates[0]);
                //                 // const end = turf.point(endF.geometry.coordinates[endF.geometry.coordinates.length - 1]);
                //                 const int = lineSlice(startF, endF, poy);
                //                 // if (index === 3) {
                //                 //     int = lineSlice(endF, startF, poy);
                //                 // }
                //                 // const options = {tolerance: 0.005, highQuality: false};
                //                 // int = simplify(int, options);
                //                 console.log(int);
                                
                //                 this.addGeoJSONLayer({'type':'FeatureCollection', 'features': [int]});

                //                 // const intsects = lineIntersect(int, next);
                //                 // console.log(intsects.features.length);
                                
                //                 // if (!intsects.features.length) {
                //                 //     int = this.spliceLine(poy, int);
                //                 // }
                                
                //                 // let useGeom = null;
                //                 // if (interMap[`${i}_${index}`]) {
                //                 //     useGeom = interMap[`${i}_${index}`];
                //                 // } else {
                //                 //     useGeom = int;
                //                 //     interMap[`${index}_${i}`] = int;
                //                 // }

                //                 // poyParts[index].intersects.push({
                //                 //     left: index,
                //                 //     right: i,
                //                 //     geom: int
                //                 // });
                //             }
                //         }
                //     });
                // });

                // poyParts.forEach((poy) => {
                //     // if (poy.difference) {
                //     //     this.addGeoJSONLayer({'type':'FeatureCollection', 'features': [poy.difference]});
                //     // }
                //     poy.intersects.forEach(int => {
                //         this.addGeoJSONLayer({'type':'FeatureCollection', 'features': [int.geom]});
                //     });
                // });

                // poyParts.forEach((poy) => {
                //     let lastGeom = poy.orign;
                //     poy.intersects.forEach(int => {
                //         if (lastGeom) {
                //             lastGeom = this.spliceLine(lastGeom, int.geom);
                //         }
                //     });
                //     poy.difference = lastGeom;
                // });

                // const options = {tolerance: 0.005, highQuality: false};
                // poyParts.forEach((poy) => {
                //     if (poy.difference) {
                //         poy.difference = simplify(poy.difference, options);
                //     }
                //     poy.intersects.forEach((int) => {
                //         int.geom = simplify(int.geom, options);
                //     });
                // });
                

                // let all = null;
                // poyParts.forEach((poy, index) => {
                //     let geom = poy.difference;
                //     poy.intersects.forEach(int => {
                //         geom = union(geom, int.geom);
                //     });
                //     geom.geometry.coordinates.push(geom.geometry.coordinates[0]);
                //     // const newPoy = turf.polygon(geom.geometry.coordinates, geom.properties);
                //     if (!all) {
                //         all = geom;
                //     } else {
                //         all = union(all, geom);
                //     }
                // });

                // console.log(all);
                
                // this.jsons[name] = newJson;
                // const layers = this.map.getLayers();
                // layers.forEach(layer => {
                //     this.map.removeLayer(layer);
                // });
                // this.addGeoJSONLayer(newJson);
            }
        }
        this.closeCX();
    }

    render () {
        return <div className='main-container'>
            <div className='shp-header'>
                <Button onClick={this.openFileSelect} theme='primary' icon='upload'>导入shp</Button>
                <Button onClick={this.openCXDialog} className='ml-10' theme='primary' icon='repeat'>面线数据抽稀</Button>
                <Button onClick={this.openProjectionList} className='ml-10' theme='primary' icon='repeat'>坐标转换</Button>
                <Button onClick={this.openMarsDialog} className='ml-10' theme='primary' icon='repeat'>火星坐标转换</Button>
                <Button onClick={this.exportGEOJSON} className='ml-10' theme='primary' icon='upload'>导出GEOJSON</Button>
            </div>
            <div className='shp-content'>
                <div id='map'>
                </div>
            </div>

            <Dialog loading visible={this.state.showModal} title='选择投影' draggable
                onConfirm={this.onConfirm} onClose={this.close}>
                <Form ref={(f) => this.form = f} labelWidth={90} pojo={this.transformParams} style={{width: 600}}>
                    <FormItem type='label' label='当前投影:' name='currentProjection' required itemStyle={{
                        'wordBreak': 'break-all',
                        lineHeight: 1
                    }}/>
                    <FormItem type='select' onChange={this.onSelectProject} filter label='转换投影:' 
                        data={epsg} textField='name' valueField='proj' name='targetCSR' required/>
                </Form>
            </Dialog>


            <Dialog loading visible={this.state.showMarsModal} title='选择投影' draggable
                onConfirm={this.onMarsConfirm} onClose={this.closeMars}>
                <Form labelWidth={90} pojo={this.transformMars} style={{width: 600}}>
                    <FormItem type='select' label='当前投影:' data={marsCoords} name='current' required />
                    <FormItem type='select' label='转换投影:' data={marsCoords} name='target' required/>
                </Form>
            </Dialog>

            <Dialog loading visible={this.state.showCXModal} title='设置抽稀参数' draggable
                onConfirm={this.onCXConfirm} onClose={this.closeCX}>
                <Form labelWidth={90} pojo={this.cxParams} style={{width: 600}}>
                    <FormItem type='text' label='抽稀精度:' name='precision' required />
                </Form>
            </Dialog>
        </div>;
    }
}

export default SHP;
